﻿using System;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MyLib.Web.UI {
	/// <summary>
	/// Paragraph
	/// </summary>
	[DefaultProperty("Text")]
	[ToolboxData("<{0}:MyPara runat=\"server\"></{0}:MyPara>")]
	public class MyPara : WebControl, ITextControl {
		/// <summary>
		/// 
		/// <para>2 - Caption, 3 - Url</para>
		/// </summary>
		private static readonly Regex ExternalLink =
			new Regex(@"\[\[(([\w\.]+)\|)?(mailto\:|(news|(ht|f)tp(s?))\://\S+)\]\]",
				RegexOptions.Compiled | RegexOptions.Singleline);

		/// <summary>
		/// 
		/// </summary>
		private const string KeywordsParameter = @"_kw";

		private string[] m_keywords = new string[0];

		/// <summary>
		/// 
		/// </summary>
		[Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
		[Localizable(true)]
		[Category("Appearance")]
		[DefaultValue("")]
		public object Value {
			get {
				return Text;
			}
			set {
				Text = value == null ? "" : value.ToString();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Bindable(BindableSupport.Yes, BindingDirection.TwoWay)]
		[Localizable(true)]
		[Category("Appearance")]
		[DefaultValue("")]
		[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
		public string Text {
			get {
				object obj2 = this.ViewState["Text"];
				if (obj2 != null) {
					return (string)obj2;
				}
				return string.Empty;
			}
			set {
				if (this.HasControls()) {
					this.Controls.Clear();
				}
				this.ViewState["Text"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		protected virtual string[] Keywords {
			get {
				if ((m_keywords == null || m_keywords.Length == 0) && Page != null) {
					var kp = Page.Request[KeywordsParameter];
					if (kp != null && kp.Length != 0) {
						m_keywords = Page.Request[KeywordsParameter].Split(',', ' ', ';');
					}
				}

				return m_keywords;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		public override void RenderBeginTag(HtmlTextWriter writer) {
			AddAttributesToRender(writer);
			writer.AddStyleAttribute("word-wrap", "break-word");
			writer.AddStyleAttribute(HtmlTextWriterStyle.Overflow, "hidden");
			writer.RenderBeginTag(HtmlTextWriterTag.P);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		public override void RenderEndTag(HtmlTextWriter writer) {
			writer.RenderEndTag();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		protected override void RenderContents(HtmlTextWriter writer) {
			if (!string.IsNullOrWhiteSpace(Text)) {
				var lines = Text.Split('\n');
				var l = lines.Length;
				for (int i = 0; i < l; ++i) {
					var line = lines[i];

					var pp = 0;
					foreach (Match m in ExternalLink.Matches(line)) {
						WriteEncodedText(
							writer,
							line.Substring(pp, m.Index - pp));
						pp = m.Index + m.Length;

						if (!m.Success) {
							WriteEncodedText(writer, m.Value);
						} else {
							var title = m.Groups[2].Value;
							var url = m.Groups[3].Value;

							if (string.IsNullOrEmpty(title))
								title = url;

							writer.AddAttribute(HtmlTextWriterAttribute.Href, url);
							writer.AddAttribute(HtmlTextWriterAttribute.Target, "_new");
							writer.AddAttribute("ext", "1");
							writer.RenderBeginTag(HtmlTextWriterTag.A);
							WriteEncodedText(writer, title.AbbreviatedTo());
							writer.RenderEndTag();
						}
					}

					if (pp < line.Length) {
						WriteEncodedText(writer, line.Substring(pp, line.Length - pp));
					}

					if (i < l - 1)
						writer.Write("<br />");
				}
			} else {
				writer.Write(" &nbsp; ");
				// writer.WriteEncodedText(Text);
			}
		} // end of RenderContents.

		/// <summary>
		/// 
		/// </summary>
		/// <param name="writer"></param>
		/// <param name="text"></param>
		private void WriteEncodedText(HtmlTextWriter writer, string text) {
			if (text == null || text.Length == 0) {
				return;
			}

			int j = 0;
			int i = j;
			while (true) {
			checkNewKeyword:
				if (i >= text.Length) {
					break;
				}

				foreach (var kw in Keywords) {
					if (StringSubMatch(text, kw, i)) {
						if (i > j) {
							writer.WriteEncodedText(text.Substring(j, i - j));
						}

						// Write keyword.
						writer.RenderBeginTag(HtmlTextWriterTag.Strong);
						writer.WriteEncodedText(text.Substring(i, kw.Length));
						writer.RenderEndTag();

						j = i + kw.Length;
						i = j;

						goto checkNewKeyword;
					}
				}

				++i;
			}

			// Write tailor.
			if (j < text.Length) {
				writer.WriteEncodedText(text.Substring(j));
			}
		} // end of WriteEncodedText.

		/// <summary>
		/// 
		/// </summary>
		/// <param name="s1"></param>
		/// <param name="s2"></param>
		/// <param name="start"></param>
		/// <returns></returns>
		private bool StringSubMatch(string s1, string s2, int start) {
			if (s1 == null && s2 == null) {
				return true;
			}

			if (s1 != null && s2 == null) {
				return false;
			}

			if (s1 == null) {
				return false;
			}

			var end = start + s2.Length;

			if (s1.Length < end) {
				end = s1.Length;
			}

			int i = start;
			int j = 0;
			while (i < end) {
				if (char.ToUpperInvariant(s1[i++]) != char.ToUpperInvariant(s2[j++])) {
					return false;
				}
			}

			return true;
		} // end of StringSubMatch.
	} // end of MyPara.
}
